﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using com.hetaoos.PacMaker.Maker;
using System.Net;
using com.hetaoos.PacMaker.Configurations;
using System.IO;
using System.Threading;
using System.Diagnostics;

#region Copyright (C) 2010 Null Studio
/*
 * Author:Null hetaoos@gmail.com
 * Blog: http://blog.hetaoos.com
 * Copyright (C) 2010 Null Studio
 * 
 * 
 * PACMaker is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * PACMaker is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with PACMaker. If not, see <http://www.gnu.org/licenses/>.
 */
#endregion

namespace com.hetaoos.PacMaker
{
    public partial class frmMain : Form
    {
        PACMaker maker = new PACMaker();
        public frmMain()
        {
            InitializeComponent();
            txtHelp.Text = help;
            foreach (ProxyType type in Enum.GetValues(typeof(ProxyType)))
            {
                cmbProxyType.Items.Add(type);
            }
            cmbProxyType.SelectedIndex = 0;
            numPort.Minimum = IPEndPoint.MinPort;
            numPort.Maximum = IPEndPoint.MaxPort;
            ReadConfig();


            proxyList_SelectedIndexChanged(this, EventArgs.Empty);
        }

        private void ReadConfig()
        {
            var data = AppConfigManager.Instance.AppConfig.ProxyItems;
            proxyList.Items.Clear();
            if (data != null && data.Count > 0)
            {
                foreach (var item in data)
                {
                    proxyList.Items.Add(item);
                }
                for (int i = 0; i < proxyList.Items.Count; i++)
                {
                    proxyList.SetItemChecked(i, (proxyList.Items[i] as ProxyItem).Checked);
                }
            }
            proxyList.Refresh();
            proxyList_SelectedIndexChanged(this, EventArgs.Empty);
            maker.GwfList = AppConfigManager.Instance.AppConfig.GwfList;
            //data = PacMaker.Properties.Settings.Default.CustomRules;
            //if (data != null && data.Count > 0)
            //{
            //    StringBuilder sb = new StringBuilder();
            //    foreach (string s in data)
            //    {
            //        sb.AppendLine(s);
            //    }
            //    txtCustomRules.Text = sb.ToString();
            //}
            txtCustomRules.Text = AppConfigManager.Instance.AppConfig.CustomRules.Replace("\n","\r\n");
            toolStripEnableCustomRules.Checked = AppConfigManager.Instance.AppConfig.EnableCustomRules;
            cmdEnableEncode.Checked = AppConfigManager.Instance.AppConfig.EnableOutputEncode;
            cmdUseSystemWebProxy.Checked = AppConfigManager.Instance.AppConfig.UseSystemWebProxy;
        }

        public bool SaveConfig()
        {
            List<ProxyItem> ls = new List<ProxyItem>();
            for (int i = 0; i < proxyList.Items.Count; i++)
            {
                ProxyItem item = proxyList.Items[i] as ProxyItem;
                item.Checked = proxyList.GetItemChecked(i);
                ls.Add(item);
            }
            AppConfigManager.Instance.AppConfig.ProxyItems = ls;
            AppConfigManager.Instance.AppConfig.CustomRules = txtCustomRules.Text;
            AppConfigManager.Instance.AppConfig.EnableCustomRules = toolStripEnableCustomRules.Checked;
            AppConfigManager.Instance.AppConfig.EnableOutputEncode = cmdEnableEncode.Checked;
            AppConfigManager.Instance.AppConfig.UseSystemWebProxy = cmdUseSystemWebProxy.Checked;
            return AppConfigManager.Instance.WriteCurrentConfig();
        }
        private void toolStripEnableCustomRules_CheckedChanged(object sender, EventArgs e)
        {
            txtCustomRules.ReadOnly = !toolStripEnableCustomRules.Checked;
        }

        private void proxyList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (proxyList.SelectedIndex < 0)
            {
                cmdMoveDown.Enabled = false;
                cmdMoveUp.Enabled = false;
            }
            else
            {
                cmdMoveUp.Enabled = proxyList.SelectedIndex > 0;
                cmdMoveDown.Enabled = proxyList.SelectedIndex < proxyList.Items.Count - 1;
            }
        }
        private void proxyList_SelectedValueChanged(object sender, EventArgs e)
        {
            proxyList_SelectedIndexChanged(this, EventArgs.Empty);
            ProxyItem item = proxyList.SelectedItem as ProxyItem;
            if (item == null)
            {
                return;
            }
            cmbProxyType.SelectedItem = item.ProxyType;
            txtIPAddress.Text = item.Address;
            numPort.Value = item.Port;

        }

        public bool CheckInput()
        {
            if (cmbProxyType.SelectedItem == null || (cmbProxyType.SelectedItem is ProxyType) == false)
            {
                cmbProxyType.Focus();
                MessageBox.Show("请选择一个有效的代理服务器类型。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            ProxyType type = (ProxyType)cmbProxyType.SelectedItem;
            if (Enum.IsDefined(typeof(ProxyType), type) == false)
            {
                MessageBox.Show("请选择一个有效的代理服务器类型。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                cmbProxyType.Focus();
                return false;
            }
            IPAddress address;
            if (txtIPAddress.TextLength == 0 || IPAddress.TryParse(txtIPAddress.Text, out address) == false)
            {
                MessageBox.Show("请输入一个有效的代理服务器地址。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                txtIPAddress.SelectAll();
                txtIPAddress.Focus();
                return false;
            }
            else
            {
                txtIPAddress.Text = address.ToString();
            }

            if (numPort.Value == 0)
            {
                MessageBox.Show("请输入一个有效的端口。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                numPort.Focus();
                return false;
            }

            return true;
        }

        private void cmdAdd_Click(object sender, EventArgs e)
        {
            if (CheckInput() == false)
            {
                return;
            }
            ProxyItem item = new ProxyItem()
            {
                Address = txtIPAddress.Text,
                Port = (int)numPort.Value,
                ProxyType = (ProxyType)cmbProxyType.SelectedItem
            };
            proxyList.Items.Add(item);
        }

        private void cmdModify_Click(object sender, EventArgs e)
        {
            if (CheckInput() == false || (proxyList.SelectedItem is ProxyItem) == false)
            {
                return;
            }
            var item = proxyList.SelectedItem as ProxyItem;
            item.Address = txtIPAddress.Text;
            item.Port = (int)numPort.Value;
            item.ProxyType = (ProxyType)cmbProxyType.SelectedItem;
            proxyList.Refresh();
        }

        private void cmdMoveUp_Click(object sender, EventArgs e)
        {
            if (proxyList.SelectedIndex < 1 || (proxyList.SelectedItem is ProxyItem) == false)
            {
                return;
            }
            var item = proxyList.SelectedItem as ProxyItem;
            int index = proxyList.SelectedIndex - 1;
            bool isChecked = proxyList.GetItemChecked(proxyList.SelectedIndex);
            proxyList.Items.Remove(item);
            proxyList.Items.Insert(index, item);
            proxyList.SetItemChecked(index, isChecked);
            proxyList.SelectedItem = item;
            proxyList.Refresh();
        }

        private void cmdMoveDown_Click(object sender, EventArgs e)
        {
            if (proxyList.SelectedIndex >= proxyList.Items.Count - 1 || (proxyList.SelectedItem is ProxyItem) == false)
            {
                return;
            }
            var item = proxyList.SelectedItem as ProxyItem;
            int index = proxyList.SelectedIndex + 1;
            bool isChecked = proxyList.GetItemChecked(proxyList.SelectedIndex);
            proxyList.Items.Remove(item);
            proxyList.Items.Insert(index, item);
            proxyList.SetItemChecked(index, isChecked);
            proxyList.SelectedItem = item;
            proxyList.Refresh();
        }

        private void proxyList_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            (proxyList.Items[e.Index] as ProxyItem).Checked = e.NewValue == CheckState.Checked;
        }

        private void cmdSave_Click(object sender, EventArgs e)
        {
            bool b = SaveConfig();
            if (b)
            {
                MessageBox.Show("配置文件保存成功。", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                MessageBox.Show("配置文件保存失败。", "失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void cmdMaker_Click(object sender, EventArgs e)
        {
            if (proxyList.Items.Count == 0)
            {
                MessageBox.Show("请添加一个或者多个代理服务器。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            List<ProxyItem> ls = new List<ProxyItem>();
            for (int i = 0; i < proxyList.Items.Count; i++)
            {
                ProxyItem item = proxyList.Items[i] as ProxyItem;
                if (proxyList.GetItemChecked(i) && item.IsValid)
                {
                    ls.Add(item);
                }
            }

            if (ls.Count == 0)
            {
                MessageBox.Show("没有选择有代理服务器，或者代理服务器无效。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            string fileName = null;
            using (SaveFileDialog saveFileDialog = new SaveFileDialog()
            {
                Filter = "PAC|*.pac|全部文件|*.*",
                FileName = DateTime.Now.ToString("yyyy-MM-dd HHmmss.pac")

            })
            {
                if (saveFileDialog.ShowDialog() != DialogResult.OK)
                {
                    return;
                }
                fileName = saveFileDialog.FileName;
            }
            string proxy = string.Join("; ", ls.Select(o => o.StorageFormat).ToArray());
            string customRules = toolStripEnableCustomRules.Checked ? txtCustomRules.Text : null;
            bool enableEncode = cmdEnableEncode.Checked;
            bool isOk = false;
            Exception error = null;

            this.UseWaitCursor = true;
            cmdMaker.Enabled = false;
            maker.UseSystemWebProxy = cmdUseSystemWebProxy.Checked;
            ThreadStart start = delegate()
            {
                try
                {
                    isOk = maker.Maker(fileName, proxy, customRules, enableEncode);
                }
                catch (Exception ex)
                {
                    error = ex;
                }
                ThreadStart end = delegate()
                {
                    this.UseWaitCursor = false;
                    cmdMaker.Enabled = true;
                    if (isOk)
                    {
                        var dr = MessageBox.Show("生成成功。是否打开输出文件夹？", "成功", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
                        if (dr == DialogResult.Yes)
                        {
                            Process proc = new Process();
                            proc.StartInfo.FileName = "explorer";
                            //打开资源管理器
                            proc.StartInfo.Arguments = string.Format(@"/select,{0}", fileName);
                            //选中"notepad.exe"这个程序,即记事本
                            proc.Start();
                        }
                    }
                    else
                    {
                        MessageBox.Show(string.Format("生成失败。错误信息:\n{0}", error), "失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                };
                this.Invoke(end);
            };
            start.BeginInvoke(null, null);
            GC.Collect();
        }

        private void cmdDelete_Click(object sender, EventArgs e)
        {
            if ((proxyList.SelectedItem is ProxyItem) == false)
            {
                return;
            }
            var item = proxyList.SelectedItem as ProxyItem;
            int index = proxyList.SelectedIndex;
            proxyList.Items.Remove(item);
            if (index >= proxyList.Items.Count)
            {
                index--;
            }
            proxyList.SelectedIndex = index;
            proxyList.Refresh();
        }

        #region DATA
        private const string help = @"PacMaker -- By Null
hetaoos@gmail.com http://blog.hetaoos.com
由于 autoproxy2pac.appspot.com 经常超载，只好自己弄个生成器了。

本程序参考、使用以下内容：
http://igfw.tk/archives/286
https://autoproxy.org/zh-CN/Rules
https://github.com/iamamac/autoproxy2pac
http://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt

目前在 gfwList 中，有如下的规则格式：

example.com
匹配：http://www.example.com/foo
匹配：http://www.google.com/search?q=www.example.com
不匹配：https://www.example.com/
用于表明字符串 example.com 为 URL 关键词。任何含关键词的 http 连接（不包括 https）皆会使用代理。

||example.com
这种规则匹配的是 example.com 及其子域名，如 http://example.com/foo 和 http://subdomain.example.com/bar，但不会匹配在 URL 其它位置出现 example.com 的情况。一般用于该站点的 IP 被封锁的情况。

|https://ssl.example.com
这种规则匹配的是所有以 https://ssl.example.com 开头的地址。一般用于某些 IP 的 HTTPS 访问被定点封锁的情况，也用于暂时应付 issue 117。

/^https?:\/\/[^\/]+example\.com/
这种规则匹配的是域名中含有 example.com 这个字符串的，是正则表达式，较不常见。一般用于该字符串被 DNS 污染的情况。

@@||example.com
这种规则的优先级最高，表示所有匹配 ||example.com 规则的网址均 禁止 代理。一般用于特殊情况。

!Foo bar
注释，以英文感叹号开头，解释说明，不起实际作用。
";
        #endregion
    }
}
